/**
*    Copyright (C) 2008  Chase Kernan 
*    chase.kernan@gmail.com
*
*    This program is free software: you can redistribute it and/or modify
*    it under the terms of the GNU General Public License as published by
*    the Free Software Foundation, either version 3 of the License, or
*    (at your option) any later version.
*
*    This program is distributed in the hope that it will be useful,
*    but WITHOUT ANY WARRANTY; without even the implied warranty of
*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*    GNU General Public License for more details.
*
*    You should have received a copy of the GNU General Public License
*    along with this program.  If not, see <http://www.gnu.org/licenses/>.
* 
**/

package com.chasekernan.hxnova.core.components;

import com.chasekernan.hxnova.core.components.ComponentSet;
import haxe.xml.Check;
import com.chasekernan.hxnova.core.minerals.MineralSet;
import com.chasekernan.hxnova.core.races.TechLevel;

/**
    Stores the combat speed and the efficiency (as ints) at each warp.
    Note: The higher the efficiency value, the more fuel it uses. i.e. an 
    efficiency of 150 uses 50% more fuel than what the formula determines for a
    given ship.
**/
class Engine extends Component {
    
    /**
        The default warp at which an engine travels for free.
    */
    public static var DEFAULT_FREE_WARP = 1;
    
    public static var WARP_MIN : Int = 0;
    public static var WARP_MAX : Int = 10;
    public static var COMBAT_SPEED_MIN : Int = 0;
    
    public var isRamscoop : Bool;
    public var efficiency : Array<Int>;
    public var combatSpeed(default, setCS) : Int;
    private function setCS(cs : Int) : Int {if(cs < COMBAT_SPEED_MIN) {throw "Combat speed must be >= "+COMBAT_SPEED_MIN;} else {combatSpeed = cs;} return combatSpeed;}
    
    public function new(name : String, ?isRamscoop : Bool, ?combatSpeed) {
        super(name);
        
        this.isRamscoop = if(isRamscoop == null) false else isRamscoop;
        
        efficiency = new Array<Int>();
        for(i in WARP_MIN...(WARP_MAX + 1)) efficiency[i] = 0;
        
        setCS(if(combatSpeed == null) COMBAT_SPEED_MIN else combatSpeed);
    }
    
    /**
        Will throw an error if the warp is not between [WARP_MIN] and 
        [WARP_MAX].
    **/
    public function getEfficiency(warp : Int) : Int {
        if(warp < WARP_MIN || warp > WARP_MAX) 
            throw "Warp must be between " + WARP_MIN + " and " + WARP_MAX + ".";
        
        return efficiency[warp];
    }
    
    /**
        Sets the efficiency of the engine at the given warp.
        Will throw an error if the warp is out of range.
    **/
    public function setEfficiency(warp : Int, value : Int) : Void {
        if(warp < WARP_MIN || warp > WARP_MAX) 
            throw "Warp must be between " + WARP_MIN + " and " + WARP_MAX + ".";
        
        efficiency[warp] = value;
    }
    
    
    /**
        Returns the highest speed at which this engine can travel for free.
    **/
    public function getHighestFreeTravelWarp() : Int {
        var i = WARP_MAX + 1;
        while (i-- > WARP_MIN) {
            if (efficiency[i] <= 0) return i;
        }
        
        return DEFAULT_FREE_WARP;
    }
    
    /**
        Return true if the engine can travel safely at the maximum warp.
        TODO: Implement a more customizable [getSafeSpeed].
    **/
    public function getIsSafeAtMaxWarp() : Bool {
        return  efficiency[WARP_MAX] <= 100;
    }
    
    public static function getXmlRules() : Rule {
        var e = new Engine("");
        
        var c = e.getChildren();
        var es = new Array<Attrib>();
        for(i in WARP_MIN...(WARP_MAX + 1)) 
            es.push(Attrib.Att("warp_"+i, FInt));
        c.push(RNode("warps", es));
        
        return RNode(e.getXmlTitle(), e.getAtt(e), RList(c, false));
    }
    
    public static function writeToXml(e : Engine) : Xml {
        var xml = Xml.parse('<' + e.getXmlTitle() + '></' + e.getXmlTitle() 
                + '>').firstChild();
        e.setAttribsAndChildren(xml, e);
        
        var warpXml = Xml.createElement("warps");
        for(i in WARP_MIN...(WARP_MAX + 1)) 
            warpXml.set('warp_' + i, Std.string(e.efficiency[i]));
        
        xml.addChild(warpXml);
        
        //Check.checkNode(xml, getXmlRules());
        
        return xml;
    }
    
    public static function readFromXml(xml : Xml) : Engine {
        try {
            //Check.checkNode(xml, getXmlRules());
            
            var e = new Engine("");
            
            e.generateFromComponentXml(xml, e);
            
            for(i in WARP_MIN...(WARP_MAX + 1)) 
                e.setEfficiency(i, Std.parseInt(xml.elementsNamed("warps")
                        .next().get('warp_'+i)));
            
            return e;
        } catch (e : Dynamic) {
            throw 'Bad xml file for engine: '+e;
        }
    }
}